#ifndef _SHARED_POINTER_H_
#define _SHARED_POINTER_H_

#include "Pointer.h"
#include "Exception.h"

namespace MySTL
{

template < typename T >
class SharedPointer : public Pointer<T>
{
public:
	SharedPointer(T* ptr = NULL);
	~SharedPointer();
	SharedPointer(const SharedPointer& obj);
	SharedPointer& operator =(const SharedPointer& obj);

	virtual void reset(T* ptr = NULL);
	bool operator == (const SharedPointer& obj) const;
	bool operator != (const SharedPointer& obj) const;

protected:
	void init_counter();
	void copy(const SharedPointer& obj);

protected:
	int* m_counter;
};

template < typename T >
SharedPointer<T>::SharedPointer(T* ptr) : Pointer<T>(ptr)
{
	m_counter = NULL;

	if (NULL != ptr)
	{
		init_counter();
		*m_counter = 1;
	}
}

template < typename T >
SharedPointer<T>::~SharedPointer()
{
	reset();
}

template < typename T >
SharedPointer<T>::SharedPointer(const SharedPointer& obj)
{
	copy(obj);
}

template < typename T >
SharedPointer<T>& SharedPointer<T>::operator =(const SharedPointer& obj)
{
	if (&obj != this)
	{
		reset();

		copy(obj);
	}

	return *this;
}

template < typename T >
void SharedPointer<T>::reset(T* ptr)
{
	if (this->m_ptr != ptr)
	{
		--*m_counter;

		if (*m_counter == 0)
		{
			delete m_counter;

			delete this->m_ptr;
		}
		m_counter = NULL;

		this->m_ptr = ptr;

		if (NULL != this->m_ptr)
		{
			init_counter();

			*m_counter = 1;
		}
	}
}

template < typename T >
bool SharedPointer<T>::operator == (const SharedPointer& obj) const
{
	return this->m_ptr == obj.m_ptr;
}

template < typename T >
bool SharedPointer<T>::operator != (const SharedPointer& obj) const
{
	return !(*this == obj);
}

template < typename T >
void SharedPointer<T>::init_counter()
{
	m_counter = new int(0);

	if (NULL == m_counter)
	{
		THROW_EXCEPTION(NoEnoughMemoryException, "No enough memory to create SharedPointer...");
	}
}

template < typename T >
void SharedPointer<T>::copy(const SharedPointer& obj)
{
	this->m_ptr = obj.m_ptr;
	m_counter = obj.m_counter;

	if (NULL != this->m_ptr && NULL != m_counter)
	{
		++*m_counter;
	}
}

}

#endif